<script setup lang="ts">
import type { AppTypeProps } from '@/types';

import {
  type ComponentInternalInstance,
  computed,
  getCurrentInstance,
  ref,
} from 'vue';

import { Icon } from '@/components/core/icon';

import { useAppStore } from '@/store';

defineOptions({
  name: 'Dock',
});

const { proxy } = getCurrentInstance() as ComponentInternalInstance;

const appStore = useAppStore();

const rightMenuVisible = ref(false);
const rightMenuLeft = ref(0);
const rightMenuBottom = ref(0);
const nowApp = ref<AppTypeProps | null>(null);
const appOpened = computed(() => {
  return (
    appStore.openAppList.length > 0 &&
    appStore.openAppList?.every((item) => item.key === nowApp.value?.key)
  );
});

const appList = computed(() => {
  return appStore.openAppList?.filter((app) => app.key === nowApp.value?.key);
});
/**
 * @description: 隐藏所有弹出的控制器
 */
const hideAllController = () => {
  rightMenuVisible.value = false;
  nowApp.value = null;
};

const openApp = (item: AppTypeProps) => {
  switch (item.key) {
    case 'system_launchpad': {
      appStore.setLaunchpad();
      break;
    }
    default: {
      appStore.openApp(item);
      break;
    }
  }
};

const dockItemsRef = ref<Element[]>([]);
const setItemsRef = (el: any, index: number) => {
  if (el) {
    dockItemsRef.value[index] = el;
  }
};

/**
 * @description: 打开右键菜单
 */
  const openMenu = (item: AppTypeProps, index: number) => {
    const $itemEl = dockItemsRef.value[index] as HTMLElement;
    const rect = $itemEl?.getBoundingClientRect();
    const menuWidth = 105; // menuWidth
    const menuHeight = 150; // estimated menu height
    
    // Center menu above the icon
    const left = rect.left + rect.width/2 - menuWidth/2;
    const bottom = window.innerHeight - rect.top + menuHeight + 10; // 10px margin
    
    rightMenuLeft.value = left;
    rightMenuBottom.value = bottom;
    rightMenuVisible.value = true;
    nowApp.value = item;
  };
const hideApp = () => {
  if (nowApp.value) {
    const index = appStore.dockAppList.findIndex(app => app.pid === nowApp.value?.pid);
    if (index !== -1) {
      const el = dockItemsRef.value[index] as HTMLElement;
      animateAppMinimize(el);
      setTimeout(() => {
        nowApp.value!.hide = true;
        appStore.hideAllApp(nowApp.value!);
      }, 300);
    }
  }
};

const showApp = (e: MouseEvent, app?: AppTypeProps) => {
  e.preventDefault();
  e.stopPropagation();
  const targetApp = app || nowApp.value;
  if (targetApp) {
    const index = appStore.dockAppList.findIndex(a => a.pid === targetApp.pid);
    if (index !== -1) {
      const el = dockItemsRef.value[index] as HTMLElement;
      animateAppMaximize(el);
      setTimeout(() => {
        if (app) {
          appStore.showApp(app);
        } else if (nowApp.value) {
          nowApp.value.hide = false;
          appStore.showApp(nowApp.value);
        }
        hideAllController();
      }, 300);
    }
  }
};
const closeApp = (e: MouseEvent, app: AppTypeProps) => {
  e.preventDefault();
  e.stopPropagation();
  if (app) {
    appStore.closeApp(app);
  }
  hideAllController();
};

const dockItemLeave = () => {
  resetElProperty();
};

const dockItemHover = (index: number) => {
  resetElProperty();
  const prev = dockItemsRef.value[index - 1];
  const beforePrev = dockItemsRef.value[index - 2];
  const prevBeforePrev = dockItemsRef.value[index - 3];
  const current = dockItemsRef.value[index] as HTMLElement;
  const next = dockItemsRef.value[index + 1];
  const afterNext = dockItemsRef.value[index + 2];
  const nextAfterNext = dockItemsRef.value[index + 3];

  if (prevBeforePrev) {
    setElProperty(prevBeforePrev as HTMLElement, 1.1, -2, 2);
  }
  if (beforePrev) {
    setElProperty(beforePrev as HTMLElement, 1.15, -5, 4);
  }
  if (prev) {
    setElProperty(prev as HTMLElement, 1.2, -9, 6);
  }

  setElProperty(current, 1.26, -14, 8);

  if (next) {
    setElProperty(next as HTMLElement, 1.2, -9, 6);
  }
  if (afterNext) {
    setElProperty(afterNext as HTMLElement, 1.15, -5, 4);
  }
  if (nextAfterNext) {
    setElProperty(nextAfterNext as HTMLElement, 1.1, -2, 2);
  }
};

const resetElProperty = () => {
  dockItemsRef.value.forEach((el) => {
    if (el) {
      setElProperty(el as HTMLElement, 1, 0, 0);
    }
  });
};

const setElProperty = (
  el: HTMLElement,
  scale: number,
  translateY: number,
  marginX: number
) => {
  el.style.transform = `scale(${scale}) translateY(${translateY}px)`;
  el.style.marginLeft = `${marginX}px`;
  el.style.marginRight = `${marginX}px`;
  el.style.transition = `transform 0.2s cubic-bezier(0.25, 0.46, 0.45, 1.5), 
                         margin 0.2s ease-out`;
};

const animateAppMinimize = (el: HTMLElement) => {
  el.style.transition = 'transform 0.3s ease-in-out';
  el.style.transform = 'scale(0.8) translateY(20px)';
  setTimeout(() => {
    el.style.opacity = '0';
  }, 200);
};

const animateAppMaximize = (el: HTMLElement) => {
  el.style.transition = 'all 0.3s ease-in-out';
  el.style.opacity = '1';
  el.style.transform = 'scale(1) translateY(0)';
};

defineExpose({
  hideAllController,
});
</script>
<template>
  <div class="footer" @click.stop="hideAllController()">
    <div class="space"></div>
    <div class="dock">
      <template v-for="(item, index) in appStore.dockAppList" :key="item.pid">
        <div v-if="
          item && proxy?.$tool.isAppInKeepList(item, appStore.dockAppList)
        " :ref="(el) => setItemsRef(el, index)" :class="appStore.nowApp.pid === item.pid ? 'jump' : ''" class="item"
          @mouseenter="dockItemHover(index)" @mouseleave="dockItemLeave" @click="
            hideAllController();
          openApp(item);
          " @contextmenu="
            hideAllController();
          openMenu(item, index);
          ">
          <i v-if="item.iconType === 'icon'" :style="{
            backgroundColor: item.iconBgColor,
            background: item.iconBgImage,
            color: item.iconColor,
          }" class="iconfont">
            <Icon :icon="item.icon" class="size-8" />
          </i>
          <i v-else :class="item.icon" :style="{
            backgroundColor: item.iconBgColor,
            backgroundImage: item.iconBgImage,
            color: item.iconColor,
          }" class="iconfont"></i>
          <div class="title">{{ item.title }}</div>
          <div v-if="proxy.$tool.isAppInOpenList(item, appStore.openAppList)" class="dot"></div>
        </div>
      </template>
    </div>
    <div class="space"></div>

    <transition key="menu">
      <div v-show="rightMenuVisible" :style="{
        left: `${rightMenuLeft}px`,
        bottom: `${rightMenuBottom}px`,
      }" class="contextmenu">
        <div v-for="(item, index) in appList" :key="index" class="item" @click="(e) => showApp(e, item)">
          <div class="item-list">
            {{ item.title }} - {{ index + 1 }}
            <div class="item-list-close" @click="(e) => closeApp(e, item)">
              <i class="iconfont-tos icon-x"></i>
            </div>
          </div>
        </div>
        <hr v-if="appList?.length" />
        <div v-if="nowApp?.multiTask" class="item" @click="nowApp && appStore.openApp(nowApp)">
          新建窗口
        </div>
        <hr v-if="nowApp?.multiTask" />
        <div v-if="appOpened && nowApp && !nowApp.hide" class="item" @click="hideApp()">
          隐藏
        </div>
        <div v-else-if="appOpened && nowApp && nowApp.hide" class="item" @click="(e) => showApp(e)">
          显示
        </div>
        <div v-if="appOpened" class="item" @click="nowApp && appStore.closeAllApp(nowApp)">
          退出
        </div>
        <div v-else class="item" @click="nowApp && appStore.openApp(nowApp)">
          打开
        </div>
      </div>
    </transition>
  </div>
</template>

<style scoped lang="scss">
@import url('./css/Dock.scss');
</style>
